home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / daemons / syslog_f.z / syslog_f / syslogd / syslogd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-17  |  27.3 KB  |  1,220 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)syslogd.c    5.45 (Berkeley) 3/2/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  *  syslogd -- log system messages
  46.  *
  47.  * This program implements a system log. It takes a series of lines.
  48.  * Each line may have a priority, signified as "<n>" as
  49.  * the first characters of the line.  If this is
  50.  * not present, a default priority is used.
  51.  *
  52.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  53.  * cause it to reread its configuration file.
  54.  *
  55.  * Defined Constants:
  56.  *
  57.  * MAXLINE -- the maximimum line length that can be handled.
  58.  * DEFUPRI -- the default priority for user messages
  59.  * DEFSPRI -- the default priority for kernel messages
  60.  *
  61.  * Author: Eric Allman
  62.  * extensive changes by Ralph Campbell
  63.  * more extensive changes by Eric Allman (again)
  64.  */
  65.  
  66. #define    MAXLINE        1024        /* maximum line length */
  67. #define    MAXSVLINE    120        /* maximum saved line length */
  68. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  69. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  70. #define TIMERINTVL    30        /* interval for checking flush, mark */
  71.  
  72. #include <sys/param.h>
  73. #include <sys/errno.h>
  74. #include <sys/ioctl.h>
  75. #include <sys/stat.h>
  76. #include <sys/wait.h>
  77. #include <sys/socket.h>
  78. #include <sys/file.h>
  79. #ifndef linux
  80. # include <sys/msgbuf.h>
  81. #endif
  82. #include <sys/uio.h>
  83. #include <sys/un.h>
  84. #include <sys/time.h>
  85. #include <sys/resource.h>
  86. #ifdef _POSIX_SOURCE
  87. # include <signal.h>
  88. #else
  89. # include <sys/signal.h>
  90. #endif
  91.  
  92. #include <netinet/in.h>
  93. #include <netdb.h>
  94.  
  95. #include <utmp.h>
  96. #include <setjmp.h>
  97. #include <stdio.h>
  98. #include <ctype.h>
  99. #include <string.h>
  100. #include <unistd.h>
  101. #include "pathnames.h"
  102.  
  103. #ifndef UT_NAMESIZE
  104. # define UT_NAMESIZE 8
  105. #endif
  106.  
  107. #define SYSLOG_NAMES
  108. #include <sys/syslog.h>
  109.  
  110. char    *LogName = _PATH_LOG;
  111. char    *ConfFile = _PATH_LOGCONF;
  112. char    *PidFile = _PATH_LOGPID;
  113. char    ctty[] = _PATH_CONSOLE;
  114.  
  115. #define FDMASK(fd)    (1 << (fd))
  116.  
  117. #define    dprintf        if (Debug) printf
  118.  
  119. #define MAXUNAMES    20    /* maximum number of user names */
  120.  
  121. /*
  122.  * Flags to logmsg().
  123.  */
  124.  
  125. #define IGN_CONS    0x001    /* don't print on console */
  126. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  127. #define ADDDATE        0x004    /* add a date to the message */
  128. #define MARK        0x008    /* this message is a mark */
  129.  
  130. /*
  131.  * This structure represents the files that will have log
  132.  * copies printed.
  133.  */
  134.  
  135. struct filed {
  136.     struct    filed *f_next;        /* next in linked list */
  137.     short    f_type;            /* entry type, see below */
  138.     short    f_file;            /* file descriptor */
  139.     time_t    f_time;            /* time this was last written */
  140.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  141.     union {
  142.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  143.         struct {
  144.             char    f_hname[MAXHOSTNAMELEN+1];
  145.             struct sockaddr_in    f_addr;
  146.         } f_forw;        /* forwarding address */
  147.         char    f_fname[MAXPATHLEN];
  148.     } f_un;
  149.     char    f_prevline[MAXSVLINE];        /* last message logged */
  150.     char    f_lasttime[16];            /* time of last occurrence */
  151.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  152.     int    f_prevpri;            /* pri of f_prevline */
  153.     int    f_prevlen;            /* length of f_prevline */
  154.     int    f_prevcount;            /* repetition cnt of prevline */
  155.     int    f_repeatcount;            /* number of "repeated" msgs */
  156. };
  157.  
  158. /*
  159.  * Intervals at which we flush out "message repeated" messages,
  160.  * in seconds after previous message is logged.  After each flush,
  161.  * we move to the next interval until we reach the largest.
  162.  */
  163. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  164. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  165. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  166. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  167.                  (f)->f_repeatcount = MAXREPEAT; \
  168.             }
  169.  
  170. /* values for f_type */
  171. #define F_UNUSED    0        /* unused entry */
  172. #define F_FILE        1        /* regular file */
  173. #define F_TTY        2        /* terminal */
  174. #define F_CONSOLE    3        /* console terminal */
  175. #define F_FORW        4        /* remote machine */
  176. #define F_USERS        5        /* list of users */
  177. #define F_WALL        6        /* everyone logged on */
  178.  
  179. char    *TypeNames[7] = {
  180.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  181.     "FORW",        "USERS",    "WALL"
  182. };
  183.  
  184. struct    filed *Files;
  185. struct    filed consfile;
  186.  
  187. int    Debug;            /* debug flag */
  188. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  189. char    *LocalDomain;        /* our local domain name */
  190. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  191. int    finet;            /* Internet datagram socket */
  192. int    LogPort;        /* port number for INET connections */
  193. int    Initialized = 0;    /* set when we have initialized ourselves */
  194. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  195. int    MarkSeq = 0;        /* mark sequence number */
  196.  
  197. extern    int errno;
  198. extern    char *ctime(), *index(), *calloc();
  199.  
  200. main(argc, argv)
  201.     int argc;
  202.     char **argv;
  203. {
  204.     register int i;
  205.     register char *p;
  206.     int funix, inetm, fklog, klogm, len;
  207. #ifndef SYSLOG_USE_FIFO
  208.     struct sockaddr_un sunx;
  209.     struct sockaddf_un fromunix;
  210. #endif /* SYSLOG_USE_FIFO */
  211.     struct sockaddr_in sin, frominet;
  212.     FILE *fp;
  213.     int ch;
  214.     char line[MAXLINE + 1];
  215.     extern int optind;
  216.     extern char *optarg;
  217.     void die(), domark(), init(), reapchild();
  218. #ifdef _POSIX_SOURCE
  219.     struct sigaction act;
  220. #endif
  221.  
  222.     while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
  223.         switch((char)ch) {
  224.         case 'd':        /* debug */
  225.             Debug++;
  226.             break;
  227.         case 'f':        /* configuration file */
  228.             ConfFile = optarg;
  229.             break;
  230.         case 'm':        /* mark interval */
  231.             MarkInterval = atoi(optarg) * 60;
  232.             break;
  233.         case 'p':        /* path */
  234.             LogName = optarg;
  235.             break;
  236.         case '?':
  237.         default:
  238.             usage();
  239.         }
  240.     if (argc -= optind)
  241.         usage();
  242.  
  243.     if (!Debug)
  244.         daemon(0, 0);
  245.     else
  246.         setlinebuf(stdout);
  247.  
  248.     consfile.f_type = F_CONSOLE;
  249.     (void) strcpy(consfile.f_un.f_fname, ctty);
  250.     (void) gethostname(LocalHostName, sizeof LocalHostName);
  251.     if (p = index(LocalHostName, '.')) {
  252.         *p++ = '\0';
  253.         LocalDomain = p;
  254.     }
  255.     else
  256.         LocalDomain = "";
  257. #ifdef _POSIX_SOURCE
  258.     act.sa_handler = die;
  259.     (void) sigemptyset (&act.sa_mask);
  260.     act.sa_flags = 0;
  261.     (void) sigaction (SIGTERM, &act, NULL);
  262.     if (Debug)
  263.         act.sa_handler = SIG_IGN;
  264.     (void) sigaction (SIGINT, &act, NULL);
  265.     (void) sigaction (SIGQUIT, &act, NULL);
  266.     act.sa_handler = reapchild;
  267.     (void) sigaction (SIGCHLD, &act, NULL);
  268.     act.sa_handler = domark;
  269.     (void) sigaction (SIGALRM, &act, NULL);
  270. #else
  271.     (void) signal(SIGTERM, die);
  272.     (void) signal(SIGINT, Debug ? die : SIG_IGN);
  273.     (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
  274.     (void) signal(SIGCHLD, reapchild);
  275.     (void) signal(SIGALRM, domark);
  276. #endif
  277.     (void) alarm(TIMERINTVL);
  278.     (void) unlink(LogName);
  279.  
  280. #ifdef SYSLOG_USE_FIFO
  281.     (void) mkfifo(LogName, 0666);
  282.     /*
  283.      * Open with O_RDWR so the open system call doesn't block.
  284.      * Could use O_RDONLY|O_NONBLOCK, but that causes the
  285.      * select system call to think the fifo is always available
  286.      * for reading (on Linux, at least).
  287.      */
  288.     funix = open(LogName, O_RDWR, 0);
  289. #else
  290.     bzero((char *)&sunx, sizeof(sunx));
  291.     sunx.sun_family = AF_UNIX;
  292.     (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
  293.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  294. #endif
  295.     if (funix < 0 ||
  296. #ifndef SYSLOG_USE_FIFO
  297.         bind(funix, (struct sockaddr *) &sunx,
  298. #ifdef linux
  299.          sizeof(sunx.sun_family)+
  300. #else
  301.          sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+
  302. #endif
  303.          strlen(sunx.sun_path)) < 0 ||
  304. #endif /* ! SYSLOG_USE_FIFO */
  305.         chmod(LogName, 0666) < 0) {
  306.         (void) sprintf(line, "cannot create %s", LogName);
  307.         logerror(line);
  308.         dprintf("cannot create %s (%d)\n", LogName, errno);
  309.         die(0);
  310.         }
  311.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  312.     if (finet >= 0) {
  313.         struct servent *sp;
  314.  
  315.         sp = getservbyname("syslog", "udp");
  316.         if (sp == NULL) {
  317.             errno = 0;
  318.             logerror("syslog/udp: unknown service");
  319.             die(0);
  320.         }
  321.         bzero((char *)&sin, sizeof(sin));
  322.         sin.sin_family = AF_INET;
  323.         sin.sin_port = LogPort = sp->s_port;
  324.         if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  325.             logerror("bind");
  326.             if (!Debug)
  327.                 die(0);
  328.         } else {
  329.             inetm = FDMASK(finet);
  330.             InetInuse = 1;
  331.         }
  332.     }
  333.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
  334.         klogm = FDMASK(fklog);
  335.     else {
  336.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  337.         klogm = 0;
  338.     }
  339.  
  340.     /* tuck my process id away */
  341.     fp = fopen(PidFile, "w");
  342.     if (fp != NULL) {
  343.         fprintf(fp, "%d\n", getpid());
  344.         (void) fclose(fp);
  345.     }
  346.  
  347.     dprintf("off & running....\n");
  348.  
  349.     init();
  350. #ifdef _POSIX_SOURCE
  351.     act.sa_handler = init;
  352.     (void) sigaction(SIGHUP, &act, NULL);
  353. #else
  354.     (void) signal(SIGHUP, init);
  355. #endif
  356.  
  357.     for (;;) {
  358.         int nfds, readfds = FDMASK(funix) | inetm | klogm;
  359.  
  360.         errno = 0;
  361.         dprintf("readfds = %#x\n", readfds);
  362.         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
  363.             (fd_set *) NULL, (struct timeval *) NULL);
  364.         if (nfds == 0)
  365.             continue;
  366.         if (nfds < 0) {
  367.             if (errno != EINTR)
  368.                 logerror("select");
  369.             continue;
  370.         }
  371.         dprintf("got a message (%d, %#x)\n", nfds, readfds);
  372.         if (readfds & klogm) {
  373.             i = read(fklog, line, sizeof(line) - 1);
  374.             if (i > 0) {
  375.                 line[i] = '\0';
  376.                 printsys(line);
  377.             } else if (i < 0 && errno != EINTR) {
  378.                 logerror("klog");
  379.                 fklog = -1;
  380.                 klogm = 0;
  381.             }
  382.         }
  383.         if (readfds & FDMASK(funix)) {
  384. #ifdef SYSLOG_USE_FIFO
  385.                 i = read(funix, line, MAXLINE);
  386. #else
  387.             len = sizeof fromunix;
  388.             i = recvfrom(funix, line, MAXLINE, 0,
  389.                 (struct sockaddr *) &fromunix, &len);
  390. #endif /* SYSLOG_USE_FIFO */
  391.             if (i > 0) {
  392.                 line[i] = '\0';
  393.                 printline(LocalHostName, line);
  394.             } else if (i < 0
  395.                    && errno != EINTR
  396. #if defined (SYSLOG_USE_FIFO) && defined (_POSIX_SOURCE)
  397.                    && errno != EAGAIN
  398. #endif
  399.                    )
  400.                 logerror("recv unix");
  401.         }
  402.         if (readfds & inetm) {
  403.             len = sizeof frominet;
  404.             i = recvfrom(finet, line, MAXLINE, 0,
  405.                 (struct sockaddr *) &frominet, &len);
  406.             if (i > 0) {
  407.                 extern char *cvthname();
  408.  
  409.                 line[i] = '\0';
  410.                 printline(cvthname(&frominet), line);
  411.             } else if (i < 0 && errno != EINTR)
  412.                 logerror("recvfrom inet");
  413.         } 
  414.     }
  415. }
  416.  
  417. usage()
  418. {
  419.     (void) fprintf(stderr,
  420.         "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
  421.     exit(1);
  422. }
  423.  
  424. /*
  425.  * Take a raw input line, decode the message, and print the message
  426.  * on the appropriate log files.
  427.  */
  428.  
  429. printline(hname, msg)
  430.     char *hname;
  431.     char *msg;
  432. {
  433.     register char *p, *q;
  434.     register int c;
  435.     char line[MAXLINE + 1];
  436.     int pri;
  437.  
  438.     /* test for special codes */
  439.     pri = DEFUPRI;
  440.     p = msg;
  441.     if (*p == '<') {
  442.         pri = 0;
  443.         while (isdigit(*++p))
  444.             pri = 10 * pri + (*p - '0');
  445.         if (*p == '>')
  446.             ++p;
  447.     }
  448.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  449.         pri = DEFUPRI;
  450.  
  451.     /* don't allow users to log kernel messages */
  452.     if (LOG_FAC(pri) == LOG_KERN)
  453.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  454.  
  455.     q = line;
  456.  
  457.     while ((c = *p++ & 0177) != '\0' &&
  458.         q < &line[sizeof(line) - 1])
  459.         if (iscntrl(c))
  460.             if (c == '\n')
  461.                 *q++ = ' ';
  462.             else if (c == '\t')
  463.                 *q++ = '\t';
  464.             else {
  465.                 *q++ = '^';
  466.                 *q++ = c ^ 0100;
  467.             }
  468.         else
  469.             *q++ = c;
  470.     *q = '\0';
  471.  
  472.     logmsg(pri, line, hname, 0);
  473. }
  474.  
  475. /*
  476.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  477.  */
  478.  
  479. printsys(msg)
  480.     char *msg;
  481. {
  482.     register char *p, *q;
  483.     register int c;
  484.     char line[MAXLINE + 1];
  485.     int pri, flags;
  486.     char *lp;
  487.  
  488.     (void) strcpy(line, _PATH_UNIX);
  489.     (void) strcat(line, ": ");
  490.     lp = line + strlen(line);
  491.     for (p = msg; *p != '\0'; ) {
  492.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  493.         pri = DEFSPRI;
  494.         if (*p == '<') {
  495.             pri = 0;
  496.             while (isdigit(*++p))
  497.                 pri = 10 * pri + (*p - '0');
  498.             if (*p == '>')
  499.                 ++p;
  500.         } else {
  501.             /* kernel printf's come out on console */
  502.             flags |= IGN_CONS;
  503.         }
  504.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  505.             pri = DEFSPRI;
  506.         q = lp;
  507.         while (*p != '\0' && (c = *p++) != '\n' &&
  508.             q < &line[MAXLINE])
  509.             *q++ = c;
  510.         *q = '\0';
  511.         logmsg(pri, line, LocalHostName, flags);
  512.     }
  513. }
  514.  
  515. time_t    now;
  516.  
  517. /*
  518.  * Log a message to the appropriate log files, users, etc. based on
  519.  * the priority.
  520.  */
  521.  
  522. logmsg(pri, msg, from, flags)
  523.     int pri;
  524.     char *msg, *from;
  525.     int flags;
  526. {
  527.     register struct filed *f;
  528.     int fac, prilev;
  529. #ifdef _POSIX_SOURCE
  530.     sigset_t bsigs;
  531. #else
  532.     int omask;
  533. #endif
  534.     int msglen;
  535.     char *timestamp;
  536.     time_t time();
  537.  
  538.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  539.         pri, flags, from, msg);
  540.  
  541. #ifdef _POSIX_SOURCE
  542.     sigemptyset(&bsigs);
  543.     sigaddset(&bsigs, SIGHUP);
  544.     sigaddset(&bsigs, SIGALRM);
  545.     (void) sigprocmask(SIG_BLOCK, &bsigs, (sigset_t *)NULL);
  546. #else
  547.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  548. #endif
  549.  
  550.     /*
  551.      * Check to see if msg looks non-standard.
  552.      */
  553.     msglen = strlen(msg);
  554.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  555.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  556.         flags |= ADDDATE;
  557.  
  558.     (void) time(&now);
  559.     if (flags & ADDDATE)
  560.         timestamp = ctime(&now) + 4;
  561.     else {
  562.         timestamp = msg;
  563.         msg += 16;
  564.         msglen -= 16;
  565.     }
  566.  
  567.     /* extract facility and priority level */
  568.     if (flags & MARK)
  569.         fac = LOG_NFACILITIES;
  570.     else
  571.         fac = LOG_FAC(pri);
  572.     prilev = LOG_PRI(pri);
  573.  
  574.     /* log the message to the particular outputs */
  575.     if (!Initialized) {
  576.         f = &consfile;
  577.         f->f_file = open(ctty, O_WRONLY, 0);
  578.  
  579.         if (f->f_file >= 0) {
  580.             fprintlog(f, flags, msg);
  581.             (void) close(f->f_file);
  582.         }
  583. #ifdef _POSIX_SOURCE
  584.         (void) sigprocmask(SIG_UNBLOCK, &bsigs, (sigset_t *)NULL);
  585. #else
  586.         (void) sigsetmask(omask);
  587. #endif
  588.         return;
  589.     }
  590.     for (f = Files; f; f = f->f_next) {
  591.         /* skip messages that are incorrect priority */
  592.         if (f->f_pmask[fac] < prilev ||
  593.             f->f_pmask[fac] == INTERNAL_NOPRI)
  594.             continue;
  595.  
  596.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  597.             continue;
  598.  
  599.         /* don't output marks to recently written files */
  600.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  601.             continue;
  602.  
  603.         /*
  604.          * suppress duplicate lines to this file
  605.          */
  606.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  607.             !strcmp(msg, f->f_prevline) &&
  608.             !strcmp(from, f->f_prevhost)) {
  609.             (void) strncpy(f->f_lasttime, timestamp, 15);
  610.             f->f_prevcount++;
  611.             dprintf("msg repeated %d times, %ld sec of %d\n",
  612.                 f->f_prevcount, now - f->f_time,
  613.                 repeatinterval[f->f_repeatcount]);
  614.             /*
  615.              * If domark would have logged this by now,
  616.              * flush it now (so we don't hold isolated messages),
  617.              * but back off so we'll flush less often
  618.              * in the future.
  619.              */
  620.             if (now > REPEATTIME(f)) {
  621.                 fprintlog(f, flags, (char *)NULL);
  622.                 BACKOFF(f);
  623.             }
  624.         } else {
  625.             /* new line, save it */
  626.             if (f->f_prevcount)
  627.                 fprintlog(f, 0, (char *)NULL);
  628.             f->f_repeatcount = 0;
  629.             (void) strncpy(f->f_lasttime, timestamp, 15);
  630.             (void) strncpy(f->f_prevhost, from,
  631.                     sizeof(f->f_prevhost));
  632.             if (msglen < MAXSVLINE) {
  633.                 f->f_prevlen = msglen;
  634.                 f->f_prevpri = pri;
  635.                 (void) strcpy(f->f_prevline, msg);
  636.                 fprintlog(f, flags, (char *)NULL);
  637.             } else {
  638.                 f->f_prevline[0] = 0;
  639.                 f->f_prevlen = 0;
  640.                 fprintlog(f, flags, msg);
  641.             }
  642.         }
  643.     }
  644. #ifdef _POSIX_SOURCE
  645.     (void) sigprocmask(SIG_UNBLOCK, &bsigs, (sigset_t *)NULL);
  646. #else
  647.     (void) sigsetmask(omask);
  648. #endif
  649. }
  650.  
  651. fprintlog(f, flags, msg)
  652.     register struct filed *f;
  653.     int flags;
  654.     char *msg;
  655. {
  656.     struct iovec iov[6];
  657.     register struct iovec *v;
  658.     register int l;
  659.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  660.  
  661.     v = iov;
  662.     if (f->f_type == F_WALL) {
  663.         v->iov_base = greetings;
  664.         v->iov_len = sprintf(greetings,
  665.             "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  666.             f->f_prevhost, ctime(&now));
  667.         v++;
  668.         v->iov_base = "";
  669.         v->iov_len = 0;
  670.         v++;
  671.     } else {
  672.         v->iov_base = f->f_lasttime;
  673.         v->iov_len = 15;
  674.         v++;
  675.         v->iov_base = " ";
  676.         v->iov_len = 1;
  677.         v++;
  678.     }
  679.     v->iov_base = f->f_prevhost;
  680.     v->iov_len = strlen(v->iov_base);
  681.     v++;
  682.     v->iov_base = " ";
  683.     v->iov_len = 1;
  684.     v++;
  685.  
  686.     if (msg) {
  687.         v->iov_base = msg;
  688.         v->iov_len = strlen(msg);
  689.     } else if (f->f_prevcount > 1) {
  690.         v->iov_base = repbuf;
  691.         v->iov_len = sprintf(repbuf, "last message repeated %d times",
  692.             f->f_prevcount);
  693.     } else {
  694.         v->iov_base = f->f_prevline;
  695.         v->iov_len = f->f_prevlen;
  696.     }
  697.     v++;
  698.  
  699.     dprintf("Logging to %s", TypeNames[f->f_type]);
  700.     f->f_time = now;
  701.  
  702.     switch (f->f_type) {
  703.     case F_UNUSED:
  704.         dprintf("\n");
  705.         break;
  706.  
  707.     case F_FORW:
  708.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  709.         l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
  710.             iov[0].iov_base, iov[4].iov_base);
  711.         if (l > MAXLINE)
  712.             l = MAXLINE;
  713.         if (sendto(finet, line, l, 0,
  714.             (struct sockaddr *)&f->f_un.f_forw.f_addr,
  715.             sizeof f->f_un.f_forw.f_addr) != l) {
  716.             int e = errno;
  717.             (void) close(f->f_file);
  718.             f->f_type = F_UNUSED;
  719.             errno = e;
  720.             logerror("sendto");
  721.         }
  722.         break;
  723.  
  724.     case F_CONSOLE:
  725.         if (flags & IGN_CONS) {
  726.             dprintf(" (ignored)\n");
  727.             break;
  728.         }
  729.         /* FALLTHROUGH */
  730.  
  731.     case F_TTY:
  732.     case F_FILE:
  733.         dprintf(" %s\n", f->f_un.f_fname);
  734.         if (f->f_type != F_FILE) {
  735.             v->iov_base = "\r\n";
  736.             v->iov_len = 2;
  737.         } else {
  738.             v->iov_base = "\n";
  739.             v->iov_len = 1;
  740.         }
  741.     again:
  742.         if (writev(f->f_file, iov, 6) < 0) {
  743.             int e = errno;
  744.             (void) close(f->f_file);
  745.             /*
  746.              * Check for errors on TTY's due to loss of tty
  747.              */
  748.             if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
  749.                 f->f_file = open(f->f_un.f_fname,
  750.                     O_WRONLY|O_APPEND, 0);
  751.                 if (f->f_file < 0) {
  752.                     f->f_type = F_UNUSED;
  753.                     logerror(f->f_un.f_fname);
  754.                 } else
  755.                     goto again;
  756.             } else {
  757.                 f->f_type = F_UNUSED;
  758.                 errno = e;
  759.                 logerror(f->f_un.f_fname);
  760.             }
  761.         }
  762. #ifndef linux
  763.          else if (flags & SYNC_FILE)
  764.             (void) fsync(f->f_file);
  765. #endif
  766.         break;
  767.  
  768.     case F_USERS:
  769.     case F_WALL:
  770.         dprintf("\n");
  771.         v->iov_base = "\r\n";
  772.         v->iov_len = 2;
  773.         wallmsg(f, iov);
  774.         break;
  775.     }
  776.     f->f_prevcount = 0;
  777. }
  778.  
  779. /*
  780.  *  WALLMSG -- Write a message to the world at large
  781.  *
  782.  *    Write the specified message to either the entire
  783.  *    world, or a list of approved users.
  784.  */
  785.  
  786. wallmsg(f, iov)
  787.     register struct filed *f;
  788.     struct iovec *iov;
  789. {
  790.     static int reenter;            /* avoid calling ourselves */
  791.     register FILE *uf;
  792.     register int i;
  793.     struct utmp ut;
  794.     char *p, *ttymsg();
  795.  
  796.     if (reenter++)
  797.         return;
  798.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  799.         logerror(_PATH_UTMP);
  800.         reenter = 0;
  801.         return;
  802.     }
  803.     /* NOSTRICT */
  804.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  805.         if (ut.ut_name[0] == '\0')
  806.             continue;
  807.         if (f->f_type == F_WALL) {
  808.             if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  809.                 errno = 0;    /* already in msg */
  810.                 logerror(p);
  811.             }
  812.             continue;
  813.         }
  814.         /* should we send the message to this user? */
  815.         for (i = 0; i < MAXUNAMES; i++) {
  816.             if (!f->f_un.f_uname[i][0])
  817.                 break;
  818.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  819.                 UT_NAMESIZE)) {
  820.                 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  821.                     errno = 0;    /* already in msg */
  822.                     logerror(p);
  823.                 }
  824.                 break;
  825.             }
  826.         }
  827.     }
  828.     (void) fclose(uf);
  829.     reenter = 0;
  830. }
  831.  
  832. #ifdef _POSIX_SOURCE
  833. void
  834. reapchild()
  835. {
  836.     int status;
  837.  
  838.     while (waitpid(0, &status, WNOHANG) > 0)
  839.         ;
  840. }
  841. #else
  842. void
  843. reapchild()
  844. {
  845.     union wait status;
  846.  
  847.     while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0)
  848.         ;
  849. }
  850. #endif
  851.  
  852. /*
  853.  * Return a printable representation of a host address.
  854.  */
  855. char *
  856. cvthname(f)
  857.     struct sockaddr_in *f;
  858. {
  859.     struct hostent *hp;
  860.     register char *p;
  861.     extern char *inet_ntoa();
  862.  
  863.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  864.  
  865.     if (f->sin_family != AF_INET) {
  866.         dprintf("Malformed from address\n");
  867.         return ("???");
  868.     }
  869.     hp = gethostbyaddr((char *)&f->sin_addr,
  870.         sizeof(struct in_addr), f->sin_family);
  871.     if (hp == 0) {
  872.         dprintf("Host name for your address (%s) unknown\n",
  873.             inet_ntoa(f->sin_addr));
  874.         return (inet_ntoa(f->sin_addr));
  875.     }
  876.     if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  877.         *p = '\0';
  878.     return (hp->h_name);
  879. }
  880.  
  881. void
  882. domark()
  883. {
  884.     register struct filed *f;
  885.     time_t time();
  886.  
  887.     now = time((time_t *)NULL);
  888.     MarkSeq += TIMERINTVL;
  889.     if (MarkSeq >= MarkInterval) {
  890.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  891.         MarkSeq = 0;
  892.     }
  893.  
  894.     for (f = Files; f; f = f->f_next) {
  895.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  896.             dprintf("flush %s: repeated %d times, %d sec.\n",
  897.                 TypeNames[f->f_type], f->f_prevcount,
  898.                 repeatinterval[f->f_repeatcount]);
  899.             fprintlog(f, 0, (char *)NULL);
  900.             BACKOFF(f);
  901.         }
  902.     }
  903.     (void) alarm(TIMERINTVL);
  904. }
  905.  
  906. /*
  907.  * Print syslogd errors some place.
  908.  */
  909. logerror(type)
  910.     char *type;
  911. {
  912.     char buf[100], *strerror();
  913.  
  914.     if (errno)
  915.         (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno));
  916.     else
  917.         (void) sprintf(buf, "syslogd: %s", type);
  918.     errno = 0;
  919.     dprintf("%s\n", buf);
  920.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  921. }
  922.  
  923. void
  924. die(sig)
  925. {
  926.     register struct filed *f;
  927.     char buf[100];
  928.  
  929.     for (f = Files; f != NULL; f = f->f_next) {
  930.         /* flush any pending output */
  931.         if (f->f_prevcount)
  932.             fprintlog(f, 0, (char *)NULL);
  933.     }
  934.     if (sig) {
  935.         dprintf("syslogd: exiting on signal %d\n", sig);
  936.         (void) sprintf(buf, "exiting on signal %d", sig);
  937.         errno = 0;
  938.         logerror(buf);
  939.     }
  940.     (void) unlink(LogName);
  941.     exit(0);
  942. }
  943.  
  944. /*
  945.  *  INIT -- Initialize syslogd from configuration table
  946.  */
  947.  
  948. void
  949. init()
  950. {
  951.     register int i;
  952.     register FILE *cf;
  953.     register struct filed *f, *next, **nextp;
  954.     register char *p;
  955.     char cline[BUFSIZ];
  956.  
  957.     dprintf("init\n");
  958.  
  959.     /*
  960.      *  Close all open log files.
  961.      */
  962.     Initialized = 0;
  963.     for (f = Files; f != NULL; f = next) {
  964.         /* flush any pending output */
  965.         if (f->f_prevcount)
  966.             fprintlog(f, 0, (char *)NULL);
  967.  
  968.         switch (f->f_type) {
  969.           case F_FILE:
  970.           case F_TTY:
  971.           case F_CONSOLE:
  972.           case F_FORW:
  973.             (void) close(f->f_file);
  974.             break;
  975.         }
  976.         next = f->f_next;
  977.         free((char *) f);
  978.     }
  979.     Files = NULL;
  980.     nextp = &Files;
  981.  
  982.     /* open the configuration file */
  983.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  984.         dprintf("cannot open %s\n", ConfFile);
  985.         *nextp = (struct filed *)calloc(1, sizeof(*f));
  986.         cfline("*.ERR\t/dev/console", *nextp);
  987.         (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
  988.         cfline("*.PANIC\t*", (*nextp)->f_next);
  989.         Initialized = 1;
  990.         return;
  991.     }
  992.  
  993.     /*
  994.      *  Foreach line in the conf table, open that file.
  995.      */
  996.     f = NULL;
  997.     while (fgets(cline, sizeof cline, cf) != NULL) {
  998.         /*
  999.          * check for end-of-section, comments, strip off trailing
  1000.          * spaces and newline character.
  1001.          */
  1002.         for (p = cline; isspace(*p); ++p);
  1003.         if (*p == NULL || *p == '#')
  1004.             continue;
  1005.         for (p = index(cline, '\0'); isspace(*--p););
  1006.         *++p = '\0';
  1007.         f = (struct filed *)calloc(1, sizeof(*f));
  1008.         *nextp = f;
  1009.         nextp = &f->f_next;
  1010.         cfline(cline, f);
  1011.     }
  1012.  
  1013.     /* close the configuration file */
  1014.     (void) fclose(cf);
  1015.  
  1016.     Initialized = 1;
  1017.  
  1018.     if (Debug) {
  1019.         for (f = Files; f; f = f->f_next) {
  1020.             for (i = 0; i <= LOG_NFACILITIES; i++)
  1021.                 if (f->f_pmask[i] == INTERNAL_NOPRI)
  1022.                     printf("X ");
  1023.                 else
  1024.                     printf("%d ", f->f_pmask[i]);
  1025.             printf("%s: ", TypeNames[f->f_type]);
  1026.             switch (f->f_type) {
  1027.             case F_FILE:
  1028.             case F_TTY:
  1029.             case F_CONSOLE:
  1030.                 printf("%s", f->f_un.f_fname);
  1031.                 break;
  1032.  
  1033.             case F_FORW:
  1034.                 printf("%s", f->f_un.f_forw.f_hname);
  1035.                 break;
  1036.  
  1037.             case F_USERS:
  1038.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  1039.                     printf("%s, ", f->f_un.f_uname[i]);
  1040.                 break;
  1041.             }
  1042.             printf("\n");
  1043.         }
  1044.     }
  1045.  
  1046.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  1047.     dprintf("syslogd: restarted\n");
  1048. }
  1049.  
  1050. /*
  1051.  * Crack a configuration file line
  1052.  */
  1053.  
  1054. cfline(line, f)
  1055.     char *line;
  1056.     register struct filed *f;
  1057. {
  1058.     register char *p;
  1059.     register char *q;
  1060.     register int i;
  1061.     char *bp;
  1062.     int pri;
  1063.     struct hostent *hp;
  1064.     char buf[MAXLINE], ebuf[100];
  1065.  
  1066.     dprintf("cfline(%s)\n", line);
  1067.  
  1068.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  1069.  
  1070.     /* clear out file entry */
  1071.     bzero((char *) f, sizeof *f);
  1072.     for (i = 0; i <= LOG_NFACILITIES; i++)
  1073.         f->f_pmask[i] = INTERNAL_NOPRI;
  1074.  
  1075.     /* scan through the list of selectors */
  1076.     for (p = line; *p && *p != '\t';) {
  1077.  
  1078.         /* find the end of this facility name list */
  1079.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  1080.             continue;
  1081.  
  1082.         /* collect priority name */
  1083.         for (bp = buf; *q && !index("\t,;", *q); )
  1084.             *bp++ = *q++;
  1085.         *bp = '\0';
  1086.  
  1087.         /* skip cruft */
  1088.         while (index(", ;", *q))
  1089.             q++;
  1090.  
  1091.         /* decode priority name */
  1092.         if (*buf == '*')
  1093.             pri = LOG_PRIMASK + 1;
  1094.         else {
  1095.             pri = decode(buf, prioritynames);
  1096.             if (pri < 0) {
  1097.                 (void) sprintf(ebuf,
  1098.                     "unknown priority name \"%s\"", buf);
  1099.                 logerror(ebuf);
  1100.                 return;
  1101.             }
  1102.         }
  1103.  
  1104.         /* scan facilities */
  1105.         while (*p && !index("\t.;", *p)) {
  1106.             for (bp = buf; *p && !index("\t,;.", *p); )
  1107.                 *bp++ = *p++;
  1108.             *bp = '\0';
  1109.             if (*buf == '*')
  1110.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1111.                     f->f_pmask[i] = pri;
  1112.             else {
  1113.                 i = decode(buf, facilitynames);
  1114.                 if (i < 0) {
  1115.                     (void) sprintf(ebuf,
  1116.                         "unknown facility name \"%s\"",
  1117.                         buf);
  1118.                     logerror(ebuf);
  1119.                     return;
  1120.                 }
  1121.                 f->f_pmask[i >> 3] = pri;
  1122.             }
  1123.             while (*p == ',' || *p == ' ')
  1124.                 p++;
  1125.         }
  1126.  
  1127.         p = q;
  1128.     }
  1129.  
  1130.     /* skip to action part */
  1131.     while (*p == '\t')
  1132.         p++;
  1133.  
  1134.     switch (*p)
  1135.     {
  1136.     case '@':
  1137.         if (!InetInuse)
  1138.             break;
  1139.         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
  1140.         hp = gethostbyname(p);
  1141.         if (hp == NULL) {
  1142.             extern int h_errno, h_nerr;
  1143.             extern char **h_errlist;
  1144.  
  1145.             logerror((u_int)h_errno < h_nerr ?
  1146.                 h_errlist[h_errno] : "Unknown error");
  1147.             break;
  1148.         }
  1149.         bzero((char *) &f->f_un.f_forw.f_addr,
  1150.              sizeof f->f_un.f_forw.f_addr);
  1151.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1152.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1153.         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
  1154.         f->f_type = F_FORW;
  1155.         break;
  1156.  
  1157.     case '/':
  1158.         (void) strcpy(f->f_un.f_fname, p);
  1159.         if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
  1160.             f->f_file = F_UNUSED;
  1161.             logerror(p);
  1162.             break;
  1163.         }
  1164.         if (isatty(f->f_file))
  1165.             f->f_type = F_TTY;
  1166.         else
  1167.             f->f_type = F_FILE;
  1168.         if (strcmp(p, ctty) == 0)
  1169.             f->f_type = F_CONSOLE;
  1170.         break;
  1171.  
  1172.     case '*':
  1173.         f->f_type = F_WALL;
  1174.         break;
  1175.  
  1176.     default:
  1177.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1178.             for (q = p; *q && *q != ','; )
  1179.                 q++;
  1180.             (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1181.             if ((q - p) > UT_NAMESIZE)
  1182.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1183.             else
  1184.                 f->f_un.f_uname[i][q - p] = '\0';
  1185.             while (*q == ',' || *q == ' ')
  1186.                 q++;
  1187.             p = q;
  1188.         }
  1189.         f->f_type = F_USERS;
  1190.         break;
  1191.     }
  1192. }
  1193.  
  1194.  
  1195. /*
  1196.  *  Decode a symbolic name to a numeric value
  1197.  */
  1198.  
  1199. decode(name, codetab)
  1200.     char *name;
  1201.     CODE *codetab;
  1202. {
  1203.     register CODE *c;
  1204.     register char *p;
  1205.     char buf[40];
  1206.  
  1207.     if (isdigit(*name))
  1208.         return (atoi(name));
  1209.  
  1210.     (void) strcpy(buf, name);
  1211.     for (p = buf; *p; p++)
  1212.         if (isupper(*p))
  1213.             *p = tolower(*p);
  1214.     for (c = codetab; c->c_name; c++)
  1215.         if (!strcmp(buf, c->c_name))
  1216.             return (c->c_val);
  1217.  
  1218.     return (-1);
  1219. }
  1220.